<template>
	<layout-base class="layout-base" @projectChange="getCatalog">
		<ul class="left-nav" slot="nav">
			<li v-if="$global.user.adminAuth == 1"><button class="btn btn-default" @click="addNav"><i class="iconfont">&#xe6e2;</i> 新建目录</button></li>
			<li v-for="(v,i) in nav" :key="i" :data-active="i===currentNav" @click.stop="onNavChange(i)">
				<span>{{v.name}}</span>
				<div v-if="$global.user.adminAuth == 1" class="ctrl-wrap">
					<i v-if="i!==0&&i!==1" class="i" title="上移" @click.stop="navMove(i,i-1,v)">&uarr;</i>
					<i v-if="i!==0&&i!==nav.length-1" class="i" title="下移" @click.stop="navMove(i,i+1,v)">&darr;</i>
					<i v-if="i!==0" title="重命名" class="iconfont i" @click.stop="navEditHandle(i,v)">&#xe6e5;</i>
					<i v-if="i!==0" class="iconfont i" title="删除" @click.stop="onDel('nav',i,v)">&#xe78c;</i>
				</div>
			</li>
		</ul>
		<div v-if="currentNav === 0">
			<h1>
				{{nav[currentNav].name}}
				<button v-if="$global.user.adminAuth == 1" class="iconfont btn btn-default" @click="addCodeHandle">&#xe6e0; 添加全局码</button>
			</h1>
			<z-table>
				<thead>
					<tr>
						<th>返回码</th>
						<th>返回信息</th>
						<th>说明</th>
						<th v-if="$global.user.adminAuth == 1">操作</th>
					</tr>
				</thead>
				<tbody>
					<tr v-for="(tr,i) in globalCode" :key="i">
						<td>{{tr.code}}</td>
						<td>{{tr.msg}}</td>
						<td>{{tr.description}}</td>
						<td v-if="$global.user.adminAuth == 1">
							<button class="iconfont btn btn-default" title="编辑" @click="editCodeHandle(i)">&#xe711;</button>
							<button class="iconfont btn btn-default ml-10" title="删除" @click="onDel('code',i, tr)">&#xe78c;</button>
						</td>
					</tr>
				</tbody>
			</z-table>
		</div>
		<div v-else>
			<h1>
				{{nav[currentNav].name}}
				<button v-if="$global.user.adminAuth == 1" class="iconfont btn btn-default" @click="addAPI">&#xe6e0; 添加API接口</button>
			</h1>
			<ul class="api-list">
				<li v-for="(api,i) in apiList" :key="i">
					<div class="api-wrap" @click.stop="apiExtend(i)">
						<div class="left">
							<label :class="['method', 'tag', 'bg-'+mapMethodStyle[api.method]]">{{api.method}}</label>
							<label v-if="api.status" class="tag">{{mapAPIStatus[api.status]}}</label>
							<div class="url" :data-status="api.status">
								{{api.url}}
								<button @click.stop="copyHandle($event, api.url)">复制</button>
								<button>{{i===currentAPI?'缩起':'展开'}}</button>
							</div>
						</div>
						<div class="right">
							{{api.description}}
							<i v-if="$global.user.adminAuth == 1" @click.stop="modifyAPI(i)" class="iconfont" title="编辑该API接口">&#xe6ef;</i>
							<i v-if="$global.user.adminAuth == 1" @click.stop="onDel('api', i, api)" class="iconfont" title="删除该API接口">&#xe6f3;</i>
						</div>
					</div>
					<div class="dropdown" :ref="'apiDropdown'+i" :data-active="i===currentAPI" :style="{height:i===currentAPI?currentAPIHeight:0}">
						<div class="wrap">
							<h4>请求参数：</h4>
							<z-table v-if="api.reqData.length">
								<thead>
									<tr>
										<th>参数</th>
										<th>值</th>
										<th>说明</th>
										<th>参数位置</th>
										<th>数据类型</th>
									</tr>
								</thead>
								<tbody>
									<tr v-for="(tr,trI) in api.reqData" :key="trI">
										<td>{{tr.label}}</td>
										<td>{{tr.required==1?'必填':'选填'}}</td>
										<td>{{tr.description}}</td>
										<td>{{tr.position}}</td>
										<td>{{tr.dataType}}</td>
									</tr>
								</tbody>
							</z-table>
							<div v-else class="gray">无</div>
							<h4>响应格式：</h4>
							<p>{{api.resType}}</p>
							<h4>响应信息：</h4>
							<pre v-if="api.resData" v-highlightjs="api.resData"><code class="javascript"></code></pre>
							<div v-else class="gray">无</div>
						</div>
					</div>
				</li>
			</ul>
		</div>
		<modal v-model="showInputModal" :title="modalInputTitle" @confirm="onInputConfrim">
			<input class="modal-input" v-model="modalInputValue" placeholder="目录名" />
		</modal>
		<modal v-model="showAddCodeModal" :title="codeModalTitle" @confirm="onCodeModalConfirm">
			<input class="modal-input" v-model="modalCode.code" placeholder="返回码" />
			<input class="modal-input" v-model="modalCode.msg" placeholder="返回信息" />
			<input class="modal-input" v-model="modalCode.description" placeholder="说明" />
		</modal>
		<modal v-model="showAPIModal" :title="apiModalTitle" @confirm="onAPIModalConfirm" width="60%">
			<div class="modal-input-wrap">
				<label>请求方法：</label>
				<select class="modal-select" v-model="api.method">
					<option value="GET">GET</option>
					<option value="POST">POST</option>
					<option value="PUT">PUT</option>
					<option value="DELETE">DELETE</option>
				</select>
			</div>
			<div class="modal-input-wrap">
				<label>开发状态：</label>
				<select class="modal-select" v-model="api.status">
					<option value="">已完成</option>
					<option value="abolish">废除</option>
					<option value="developing">开发中</option>
				</select>
			</div>
			<div class="modal-input-wrap">
				<label>请求路径：</label>
				<input class="modal-input" v-model="api.url" placeholder="接口路径" />
			</div>
			<div class="modal-input-wrap">
				<label>描述：</label>
				<input class="modal-input" v-model="api.description" placeholder="描述" />
			</div>
			<div class="modal-input-wrap has-rows reqData">
				<label>请求参数：</label>
				<z-table>
					<thead v-if="api.reqData.length">
						<tr>
							<th>参数</th>
							<th>值</th>
							<th>说明</th>
							<th>参数位置</th>
							<th>数据类型</th>
							<th>操作</th>
						</tr>
					</thead>
					<tbody>
						<tr v-for="(tr,i) in api.reqData" :key="i">
							<td><input v-model="tr.label" /></td>
							<td>
								<select v-model="tr.required">
									<option value="0">选填</option>
									<option value="1">必填</option>
								</select>
							</td>
							<td><input v-model="tr.description" /></td>
							<td>
								<select v-model="tr.position">
									<option value="path">path</option>
									<option value="query">query</option>
									<option value="formData">formData</option>
								</select>
							</td>
							<td>
								<select v-model="tr.dataType">
									<option value="string">string</option>
									<option value="number">number</option>
									<option value="boolean">boolean</option>
									<option value="array">array</option>
									<option value="json">json</option>
									<option value="date">date</option>
								</select>
							</td>
							<td><i class="iconfont delete" title="移除" @click="removeAPIReqData(i)">&#xe6f3;</i></td>
						</tr>
						<tr class="modal-table-add-reqdata-btn" @click="addNewAPIReqData"><td colspan="6">+ 添加参数</td></tr>
					</tbody>
				</z-table>
			</div>
			<div class="modal-input-wrap">
				<label>响应格式：</label>
				<select class="modal-select" v-model="api.resType">
					<option value="application/json">application/json</option>
					<option value="multipart/form-data">multipart/form-data</option>
					<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
					<option value="text/xml">text/xml</option>
				</select>
			</div>
			<div class="modal-input-wrap has-rows resData">
				<label>响应数据：</label>
				<textarea class="modal-input" v-model="api.resData" placeholder="请输入响应数据" rows="6"></textarea>
			</div>
		</modal>
		<loading v-model="showLoading"></loading>
	</layout-base>
</template>

<script>
	export default{
		async created() {
			//刷新保留活跃导航
			this.query = this.$router.history.current.query
		},
		mounted() {
			//移除当前展开的API
			this.currentAPI = -1
		},
		data(){
			return{
				//加载
				showLoading: false,
				//路径参数
				query: null,
				//当前项目
				currentProject: null,
				//导航
				currentNav:0,
				modalInputValue: '',
				modalInputTitle: '新建目录',
				showInputModal: false,
				currentEditNav: -1,
				//全局码
				codeModalTitle: '添加全局返回码',
				modalCode: {
					code: null,
					msg: '',
					description: ''
				},
				showAddCodeModal: false,
				currentEditCode: -1,
				//添加或编辑API
				showAPIModal: false,
				apiModalTitle: '添加API',
				currentEditAPI: -1,
				api:{
					method:'GET',
					status:'',
					url:'',
					description:'',
					resType:'application/json',
					reqData:[],
					resData:''
				},
				//当前展开的API与高度
				currentAPIHeight: 0,
				currentAPI:-1,
				//API模拟数据
				nav:[{name:'全局返回码', _id:0}],
				globalCode:[],
				apiList:[],
				mapAPIStatus:{
					'abolish':'废除',
					'developing':'开发中'
				},
				mapMethodStyle:{
					'POST':'primary',
					'PUT':'info',
					'GET':'success',
					'DELETE':'danger'
				}
			}
		},
		methods:{
			//监听获取项目
			async getCatalog(project){
				this.showLoading = true
				this.currentProject = project
				//获取全局码
				this.$http.get(`/api/globalcode/${project._id}`)
				.then(res=>{
					this.globalCode = res
				})
				.catch(err=>{
					console.log('获取全局码失败：', err)
				})
				//获取目录
				await this.$http.get(`/api/catalog/${project._id}`)
				.then(res=>{
					this.nav = [{name:'全局返回码', _id:0}, ...res.sort((x,y)=>x.sort-y.sort)]
					if(this.query.nav){
						this.currentNav = parseInt(this.query.nav)
						this.getAPIList()
					}
				})
				.catch(err=>{
					console.log('获取目录列表失败：', err)
				})
				this.showLoading = false
			},
			//添加全局返回码
			addCodeHandle(){
				this.currentEditCode = -1
				this.codeModalTitle = '添加全局返回码'
				this.modalCode = {
					code: null,
					msg: '',
					description: ''
				}
				this.showAddCodeModal = true
			},
			//修改全局返回码
			editCodeHandle(i){
				this.codeModalTitle = '修改全局返回码'
				this.currentEditCode = i
				this.modalCode = Object.assign({},this.globalCode[i])
				this.showAddCodeModal = true
			},
			//全局返回码确认
			async onCodeModalConfirm(){
				if(this.modalCode.code===null){
					this.$Message({content:'返回码不能为空',type:'warning'})
					return false
				}
				this.showLoading = true
				if(this.currentEditCode === -1){
					//添加
					await this.$http.post('/api/globalcode', Object.assign({projectId:this.currentProject._id}, this.modalCode))
					.then(res=>{
						this.globalCode.push(res)
						this.$Message({type:'success', content:'添加成功'})
					})
					.catch(err=>{
						console.log('添加全局返回码失败：', err)
					})
				}else{
					//修改
					await this.$http.put(`/api/globalcode/${this.modalCode._id}`, {
						code: this.modalCode.code,
						msg: this.modalCode.msg,
						description: this.modalCode.description
					})
					.then(res=>{
						this.globalCode[this.currentEditCode] = this.modalCode
					})
					.catch(err=>{
						console.log('全局码修改失败：', err)
					})
				}
				this.showAddCodeModal = false
				this.showLoading = false
			},
			//删除操作
			async onDel(type, i, v){
				if(window.confirm('确认删除？')){
					this.showLoading = true
					switch(type){
						case 'code':
							await this.$http.delete(`/api/globalcode/${v._id}`)
							.then(res=>{
								this.globalCode.splice(i, 1)
							})
							.catch(err=>{
								console.log('全局码删除失败：', err)
							})
							break
						case 'nav':
							await this.$http.delete(`/api/catalog/${v._id}`)
							.then(res=>{
								if(this.currentNav === i){
									this.currentNav = 0
									this.$router.push('/')
								}
								this.nav.splice(i, 1)
							})
							.catch(err=>{
								console.log('目录删除失败：', err)
							})
							break
						case 'api':
							await this.$http.delete(`/api/api/${v._id}`)
							.then(res=>{
								this.apiList.splice(i,1)
							})
							.catch(err=>{
								console.log('删除API接口失败：', err)
							})
							break
					}
					this.showLoading = false
				}
			},
			//增加目录
			addNav(){
				this.modalInputValue = ''
				this.modalInputTitle = '新建目录'
				this.currentEditNav = -1
				this.showInputModal = true
			},
			//修改目录
			navEditHandle(i){
				this.modalInputValue = this.nav[i].name
				this.modalInputTitle = '重命名目录'
				this.currentEditNav = i
				this.showInputModal = true
			},
			//移动目录位置
			async navMove(i, j, v){
				this.showLoading = true
				//交换sort值
				await this.$http.put(`/api/catalog/move/${v._id}/${this.nav[j]._id}`, {sort:j, sort2:i})
				.then(res=>{
					this.nav = this.$zp.arrExChange(this.nav, i, j).slice()
				})
				.catch(err=>{
					console.log('目录移动失败：', err)
				})
				this.showLoading = false
			},
			//切换目录
			async onNavChange(i){
				this.currentNav = i
				this.$router.push({
					path: '/',
					query: {nav: i}
				})
				if(i===0)return false
				this.getAPIList()
			},
			// 确认增加/修改目录
			async onInputConfrim(){
				this.showLoading = true
				const requestData = {projectId: this.currentProject._id, name: this.modalInputValue}
				if(this.currentEditNav === -1){
					await this.$http.post('/api/catalog', requestData)
					.then(res=>{
						this.nav.push({
							name: this.modalInputValue,
							_id: res._id
						})
						this.currentNav = this.nav.length-1
						this.$router.push({
							path: '/',
							query: {nav: this.currentNav}
						})
					})
					.catch(err=>{
						console.log('新建目录失败：', err)
					})
				}else{
					await this.$http.put(`/api/catalog/${this.nav[this.currentEditNav]._id}`, requestData)
					.then(res=>{
						this.nav[this.currentEditNav].name = this.modalInputValue
					})
					.catch(err=>{
						console.log('修改目录失败：', err)
					})
				}
				this.showInputModal = false
				this.showLoading = false
			},
			// 确认添加/修改api
			async onAPIModalConfirm(){
				this.showLoading = true
				if(this.currentEditAPI===-1){
					await this.$http.post('/api/api', Object.assign({
						projectId: this.currentProject._id,
						navId: this.nav[this.currentNav]._id
					}, this.api))
					.then(res=>{
						this.apiList.push(res)
						this.$Message({type:'success',content:'添加成功'})
					})
					.catch(err=>{
						console.log('添加API接口失败：', err)
					})
				}else{
					await this.$http.put(`/api/api/${this.apiList[this.currentEditAPI]._id}`, {
						method: this.api.method,
						status: this.api.status,
						url: this.api.url,
						description: this.api.description,
						resType: this.api.resType,
						reqData: this.api.reqData,
						resData: this.api.resData
					})
					.then(res=>{
						this.apiList[this.currentEditAPI] = this.api
					})
					.catch(err=>{
						console.log('API接口修改失败：', err)
					})
				}
				this.showAPIModal = false
				this.showLoading = false
			},
			//获取API接口列表
			async getAPIList(){
				this.showLoading = true
				await this.$http.get(`/api/api/${this.nav[this.currentNav]._id}`)
				.then(res=>{
					this.apiList = res
				})
				.catch(err=>{
					console.log('获取API列表失败：', err)
				})
				this.showLoading = false
			},
			//添加api
			addAPI(){
				this.currentEditAPI = -1
				this.apiModalTitle = '添加API'
				this.api = {
					method:'GET',
					status:'',
					url:'',
					description:'',
					resType:'application/json',
					reqData:[],
					resData:''
				}
				this.showAPIModal = true
			},
			//修改API
			modifyAPI(i){
				this.currentEditAPI = i
				this.apiModalTitle = '修改API'
				this.api = Object.assign({},this.apiList[i])
				this.showAPIModal = true
			},
			//复制api
			copyHandle(e, url){
				this.$copyText(url, e.target).then(()=>{
					this.$Message({
						type:'success',
						content:'复制成功'
					})
				}).catch(e=>{
					console.log(e)
					this.$Message({
						type:'error',
						content:'复制失败'
					})
				})
			},
			//展开或收缩API
			apiExtend(i){
				if(this.currentAPI === i) {
					this.currentAPI = -1
					return false
				}
				const ele = this.$refs['apiDropdown'+i][0]
				this.currentAPIHeight = ele.scrollHeight + 'px'
				this.currentAPI = i
			},
			//模态框中添加请求参数
			addNewAPIReqData(){
				this.api.reqData.push({label:'',value:'',description:'',position:'path',dataType:'string',required:0})
			},
			//模态框中移除请求参数
			removeAPIReqData(i){
				this.api.reqData.splice(i, 1)
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '../assets/css/base.scss';
	.layout-base{
		h1{
			display: flex;
			align-items: center;
			button{
				margin-left: 20px;
				font-size: 12px;
				padding: .4em 1em;
				color: #999;
				border-color: #e5e5e5;
				&:hover{
					border-color: #ccc;
					color: #000;
				}
			}
		}
	}
	.left-nav{
		padding: 10px 0;
		li{
			padding: 10px 20px;
			cursor: pointer;
			color: #666;
			display: flex;
			align-items: center;
			justify-content: space-between;
			&:hover{
				color: #000;
				.ctrl-wrap{
					display: flex;
				}
			}
			&[data-active="true"] span{
				color: $primary;
			}
		}
		.btn{
			width: 100%;
			display: block;
		}
	}
	.ctrl-wrap{
		align-items: center;
		display: none;
		.i{
			display: inline-block;
			height: 1.4em;
			width: 1.4em;
			display: flex;
			align-items: center;
			justify-content: center;
			font-size: 12px;
			color: #999;
			margin-left: 5px;
			background: #f5f5f5;
			&:hover{
				color: #000;
			}
		}
	}
	.api-list{
		.right .iconfont{
			margin-left: 15px;
			color: #ccc;
			font-size: 18px;
			&:hover{
				color: #000;
			}
		}
		li{
			margin-bottom: 10px;
		}
		.api-wrap{
			border: solid 1px #eee;
			display: flex;
			justify-content: space-between;
			width: 100%;
			padding-right: 1em;
			align-items: center;
			cursor: pointer;
			box-sizing: border-box;
			.right{
				display: flex;
				align-items: center;
			}
			.left{
				display: flex;
				align-items: center;
			}
		}
		.tag{
			font-size: 12px;
			padding: 0 5px;
			background: #e5e5e5;
			display: inline-block;
			height: 36px;
			line-height: 38px;
			min-width: 56px;
			text-align: center;
			margin: -1px;
		}
		.url{
			margin: 0 0 0 15px;
			&[data-status="abolish"]{
				text-decoration: line-through;
			}
			button{
				font-size: 12px;
				background: none;
				margin-left: 5px;
				border: solid 1px #eee;
				color: #999;
				border-radius: 3px;
				cursor: pointer;
				&:hover{
					background: #f5f5f5;
				}
			}
		}
	}
	.dropdown{
		height: 0;
		overflow: hidden;
		transition: height .3s;
		border: solid 1px #eee;
		border-top: 0;
		border-bottom: 0;
		.wrap{
			padding: 1em;
		}
		&[data-active="true"]{
			border-bottom: solid 1px #eee;
			height: auto;
		}
		h4{
			font-weight: bold;
		}
	}
	.modal-input-wrap{
		display: flex;
		align-items: center;
		label{
			dislay: inline-block;
			min-width: 90px;
			color: #999;
		}
		&.has-rows{
			align-items: flex-start;
		}
		&.resData label{
			margin-top: 1.4em;
		}
		&.reqData{
			margin: 1em 0;
			label{
				margin-top: 1em;
			}
		}
		.modal-table-add-reqdata-btn{
			text-align: center;
			background: #f2f2f2;
			cursor: pointer;
			&:hover{
				background: #eee;
			}
		}
		table{
			input,select{
				border: solid 1px #e5e5e5;
				border-radius: 3px;
			}
			input{
				padding: 0 .2em;
			}
		}
		.delete{
			color: #999;
			text-align: center;
			display: block;
			cursor: pointer;
			&:hover{
				color: #000;
			}
		}
	}
</style>
